#include <EEPROM.h>
#include <MemoryFree.h>
#include <Encoder.h>

/*
 * TimeRTCSet.pde
 * example code illustrating Time library with Real Time Clock.
 *
 * RTC clock is set in response to serial port time message 
 * A Processing example sketch to set the time is inclided in the download
 */
#include <SoftwareSerial.h>
#include <Time.h>  
#include <Wire.h>  
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t
#include <Adafruit_MCP23008.h>
#include <Fans.h>

#define LCD 8
#define ENCA 6 
#define ENCB 5
#define ENCP 7

#define ENDA 3 
#define ENDB 2
#define ENDP 4

#define BAR1_PWM 11
#define BAR1_PWR 4

#define BAR2_PWM 10
#define BAR2_PWR 5

#define BAR0_PWM 9
#define BAR0_PWR 6

#define FAN0 0
#define FAN1 1
#define FAN2 2
#define FAN3 3

SoftwareSerial mySerial(12, LCD);

byte encA_pos = 0;
unsigned long prev = 0;
unsigned long pmillis = 0;
unsigned long lastSched = 0;

byte encA_pos1 = 0;

byte ln2Cursor;

unsigned long prevMillis;
int progItem;


Adafruit_MCP23008 mcp;
Encoder KnobA(ENCA, ENCB, ENCP);
Encoder KnobB(ENDA, ENDB, ENDP);

const int lvls[] = { 200, 1000, 5000, 10000, 20000, 25000, 30000, 35000, 40000, 50000, 60000 };
   
typedef struct  { 
  unsigned int Time;           //0 trigger time - minutes from midnight 
  byte Bar;           //2 ID of light bar
  boolean Active;     //3 activated
  int Slope;          //4 slope in tenths of second
  byte Value;         //6 target value
} 	ltSched_t, LightSchedule, *ltSchedPtr_t;

typedef struct {
  int Target;
  byte Current;
  int Slope;
  byte PowerPin;
  byte DimPin;
  time_t ProgTime;
  unsigned long LastPoll;
} ltBar_t, LightBar, *ltBarPtr_t;


  char* menu[]  = {"AUTO       ",
                   "MANUAL     ",
                   "ADVANCE    ",
                   "FANS       ",
                   "SET TIME   ",
                   "PROGRAM ",
                   "FREE MEM   " };
                   
   byte menuItem = 0;
   byte menuSelect = 0;
   byte timePos = 0;
   char cursorPos[8] = "";
   
   tmElements_t setTm;
   
   
   Fan fans[4] = { Fan(FAN0,0, &setMCPPin ), Fan(FAN1,2, &setMCPPin ), Fan(FAN2,4, &setMCPPin ), Fan(FAN3,6, &setMCPPin ) };
   ltSched_t sched[20];
   ltBar_t bar[3];


void PollLights()
{
  
 // Adjust values  - go through each bar
 for (int x = 0; x < 3; x++ ) {
   boolean changed = false;
   
   if ( bar[x].Target !=  bar[x].Current && 
        millis() > bar[x].LastPoll + lvls[ bar[x].Slope  ] 
      ) 
   {
     
     if ( bar[x].Target > bar[x].Current ) {
       changed = true;
       bar[x].Current++;
     } else if ( bar[x].Target < bar[x].Current )  {
       changed = true;
       bar[x].Current--;
     }
     bar[x].LastPoll = millis();
   }
   
   if ( changed == true ) {
    if ( bar[x].Current == 0 ) {
       mcp.digitalWrite(bar[x].PowerPin, LOW);
    } else {
       mcp.digitalWrite(bar[x].PowerPin, HIGH);
    }
    
    analogWrite(bar[x].DimPin, bar[x].Current );  
   }
 }
 
 // check to see if new targets should be set


 // if changes, write them to serial for diagnostics 
  
  
}

void InitBar() {
  bar[0].PowerPin = BAR0_PWR;
  bar[0].DimPin = BAR0_PWM;
  bar[0].Slope = 0;
  bar[0].Current = 0;
  bar[0].Target = 0;
  
  bar[1].PowerPin = BAR1_PWR;
  bar[1].DimPin = BAR1_PWM;
  bar[1].Slope = 0;
  bar[1].Current = 0; 
  bar[1].Target = 0;
  
  bar[2].PowerPin = BAR2_PWR;
  bar[2].DimPin = BAR2_PWM;
  bar[2].Slope = 0;
  bar[2].Current = 0;
  bar[2].Target = 0;
  
  mcp.digitalWrite( BAR0_PWR, LOW); 
  mcp.digitalWrite( BAR1_PWR, LOW); 
  mcp.digitalWrite( BAR2_PWR, LOW); 
  
  analogWrite( BAR0_PWM, 0);
  analogWrite( BAR1_PWM, 0);
  analogWrite( BAR2_PWM, 0);
  Serial.print ("INIT\n");
  
  lastSched = 0;
  UpdateSchedule();
  
  bar[ 0 ].Slope = 0;
  bar[ 1 ].Slope = 0;
  bar[ 2 ].Slope = 0;
  lastSched = millis();
}

void ResetProg ()
{
  for (int x = 0; x < 3; x++ ) {
    bar[x].ProgTime = 0;
    bar[x].Slope = 0;
  }  
}


void UpdateSchedule() {
  
  if (millis() > lastSched ) {
    
  Serial.print ("UpdateSchedule()\n");
  
 
  int currTime = ( hour() * 60 ) + minute();
  
  for ( int x = 0; x < 20; x++ ) {
     time_t t = now();
     breakTime( t, setTm);
     if ( sched[x].Active == true ) {
       if( sched[x].Time < currTime )  {
         if ( sched[x].Time > bar[ sched[x].Bar ].ProgTime ) {
            bar[ sched[x].Bar ].Target = sched[x].Value;
            bar[ sched[x].Bar ].ProgTime = sched[x].Time;
            bar[ sched[x].Bar ].Slope = sched[x].Slope;
            Serial.print ("Program Update ");
            Serial.print ( sched[x].Bar );
            Serial.print ( ": ");
            Serial.print ( sched[x].Value );
            Serial.print ("\n");
         }
       }
     }
  
  }
  
  lastSched = millis() + 10000 ;
  }
  
}

void SaveSchedule( int x ) {
  
  byte s;
  s = highByte( sched[x].Time );
  EEPROM.write ( (x * 7 ) + 10, s );
  
  s = lowByte( sched[x].Time );
  EEPROM.write( (x * 7) + 10 + 1, s );
  
  s = sched[x].Bar;
  EEPROM.write( (x * 7 ) + 10 + 2, s );  
  
  s = sched[x].Active;
  EEPROM.write( (x * 7 ) + 10 + 3, s );
  
  s = highByte( sched[x].Slope );
  EEPROM.write( (x * 7 ) + 10 + 4, s );
  
  s = lowByte( sched[x].Slope );
  EEPROM.write( (x * 7 ) + 10 + 5, s );

  s =  sched[x].Value;
  EEPROM.write( (x * 7 ) + 10 + 6, s );

}

void LoadSchedule() {
  
   for ( int x = 0; x < 20; x++ ) {
      byte s;
      s = EEPROM.read( (x * 7) + 10 );
      sched[x].Time = (s << 8 );
      
      s = EEPROM.read( (x * 7) + 10 + 1 );
      sched[x].Time = sched[x].Time + s;
      
      // initialize memory if out of range.
      if ( sched[x].Time > 1440 ) {
        sched[x].Time = 0;
      }
      
      s = EEPROM.read( (x * 7) + 10 + 2 );
      if ( s > 2 ) {
       s = 0; 
      }
      sched[x].Bar = s;
      
      s = EEPROM.read( (x * 7) + 10 + 3 );
      if ( s > 1 ) {
       s = 0; 
      }
      sched[x].Active = s;
      
      s = EEPROM.read( (x * 7) + 10 + 4 );
      sched[x].Slope = ( s << 8 );
      
      s = EEPROM.read( (x * 7) + 10 + 5 );
      sched[x].Slope = sched[x].Slope + s;
      
      if ( sched[x].Slope > 9 ) {
         sched[x].Slope = 1;
      } 
      if ( sched[x].Slope < 1 ) {
        sched[x].Slope = 1;
      }
      
      s = EEPROM.read( (x * 7) + 10 + 6 );
      sched[x].Value = s;
      
      
    }
  
}


void setup()  {
  Serial.write ("START");
  
  KnobA.setPulse( &menuEncoder );
  KnobA.setButton(&menuButton );
  
  KnobB.setPulse( &empty);
  KnobB.setButton( &empty );
  
  
  Serial.begin(9600);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
    Serial.println("Unable to sync with the RTC");
  else
    Serial.println("RTC has set the system time");  


  mcp.begin();      // use default address 0

  mcp.pinMode(0, OUTPUT);
  mcp.pinMode(1, OUTPUT);
  mcp.pinMode(2, OUTPUT);
  mcp.pinMode(3, OUTPUT);
  mcp.pinMode(4, OUTPUT);
  mcp.pinMode(5, OUTPUT);
  mcp.pinMode(6, OUTPUT);
  mcp.pinMode(7, OUTPUT);    

  
  pinMode(ENDA, INPUT);
  pinMode(ENDB, INPUT);
  pinMode(ENDP, INPUT);
  
  
  pinMode(LCD, OUTPUT);
  
  for ( int x = 0; x < 4; x++ ) {
    fans[x].begin();
  }
  
  LoadSchedule();
  
  mySerial.begin(9600);      // 9600 baud is chip comm speed

  mySerial.print("?G216");   // set display geometry,  2 x 16 characters in this case
  delay(500);                // pause to allow LCD EEPROM to program

  mySerial.print("?Bff");    // set backlight to ff hex, maximum brightness
  delay(1000);   

  mySerial.print("?f");    // set backlight to ff hex, maximum brightness

  mySerial.print("?c0"); 

  InitBar();
  
}

void loop()
{
  KnobA.poll();
  KnobB.poll();
  
  if ( menuItem == 4 &&  millis() > prevMillis + 1000 ) {
    //displayTimeSet(true);  
    prevMillis = millis();
  } 
  
  else if ( menuItem == 6 &&  millis() > prevMillis + 1000 ) {
    displayFreeMem();
    prevMillis = millis();
  }
  
  PollLights();
  
  if ( menuItem != 1 )
  UpdateSchedule();
  
  
 
  if (millis() > prevMillis + 1000 ) {
    
    Serial.print("F: ");
    Serial.print( bar[0].Current );
    Serial.print( "/" );
    Serial.print( bar[0].Target );
    Serial.print( " " );
    
    Serial.print("M: ");
    Serial.print( bar[1].Current );
    Serial.print( "/" );
    Serial.print( bar[1].Target );
    Serial.print( " " );
    
    Serial.print("B: ");
    Serial.print( bar[2].Current );
    Serial.print( "/" );
    Serial.print( bar[2].Target );
    Serial.print( "\n" );
    prevMillis = millis();
  }
  
  if(Serial.available())
  {
    time_t t = processSyncMessage();
    if(t >0)
    {
      RTC.set(t);   // set the RTC and the system time to the received value
      setTime(t);          
    }
  }



  if (millis() > prev + 1000) {
    prev = millis();
    digitalClockDisplay(); 
    
      if ( menuItem == 1 )
    manualDisplay();

  }
  

 
}

void digitalClockDisplay(){
  // digital clock display of the time
  mySerial.print("?x11?y0");              // move cursor to beginning of line 1
  printDigits2(hour());
//  mySerial.print( hour() );
  printDigits(minute());
  mySerial.print( cursorPos );
 

}

void  dualDig( int digits ) {
  if ( digits < 10 ) {
      mySerial.print('0');
  }
   mySerial.print (digits );
   
}


void displayFreeMem() {
  mySerial.print("?x03?y1");
  mySerial.print(freeMemory());
  
}

void setMCPPin( uint8_t p, uint8_t v) {
 mcp.digitalWrite( p, v); 
  
}

void displayFansSet () {
  //              0123456789012345
  mySerial.print("?x00?y11:  2:  3:  4: ");
  for ( int x = 0; x < 4; x++ ) {
     mySerial.print("?x");
     dualDig( (x * 4 ) + 2 );
     switch( fans[x].getMode() ) {
       case fanOn:
           mySerial.print( '1' );
           break;
       case fanOff:
           mySerial.print( '0' );
           break;
       case fanAuto:
           mySerial.print( 'A' );
           break;
         
     }
     
     mySerial.print( cursorPos );
     
  }
}

void progEncoder ( boolean chg ) {
  if (timePos == 0) {
    if ( chg == true ) 
       progItem++;
    else 
       progItem--;
    
    if ( progItem  > 20 ) { 
      progItem = 20;
    }
    if (progItem < 1 ) {
      progItem = 1;
    }
    progDisplay(progItem);

  }  else if ( timePos == 1 ) {
   if ( sched[progItem - 1].Active == true ) {
       sched[progItem - 1].Active = false; 
   } else {
      sched[progItem - 1].Active = true;
   }
   progDisplay(progItem);
   
  } else if ( timePos == 2 ) {
    
    if ( chg == true && sched[progItem - 1].Time < (1440 - 60) ) {
      sched[progItem - 1].Time += 60;   
    } else if ( chg == false && sched[progItem - 1].Time > 60 ) {
      sched[progItem - 1].Time -= 60;      
    }
    progDisplay(progItem);
    
  } else if ( timePos == 3 ) {
   
      if ( chg == true ) {
       
        if ( sched[progItem - 1].Time % 60 <  59 ) {
          sched[progItem - 1].Time += 1;
       }
       
    } else if ( chg == false ) {
      if ( sched[progItem - 1].Time % 60  > 0 ) {
        sched[progItem - 1].Time -= 1;      
      }
    }
    progDisplay(progItem);
    
    
  } else if ( timePos == 4 ) {
    if ( chg == true && sched[progItem - 1].Bar < 2 ) {
        sched[progItem - 1].Bar++;  
    } else if ( chg == false && sched[progItem - 1].Bar != 0 ) {
       sched[progItem - 1].Bar--; 
    }
    progDisplay(progItem);
    
    
  } else if ( timePos == 5 ) {
    
    byte inc = 10;
    if ( millis()  > pmillis + 100 ) {
      inc = 1;
     
    }
    
    pmillis = millis();
    
    if ( chg == true && sched[progItem - 1].Value < 255 ) {
      if (sched[progItem-1].Value < 240)  
          sched[progItem - 1].Value += inc;  
      else
          sched[progItem-1].Value ++;
     
    } else if ( chg == false && sched[progItem - 1].Value != 0 ) {
      
      if (sched[progItem-1].Value > 12)  
          sched[progItem - 1].Value -= inc;  
      else
          sched[progItem-1].Value --;
    }
    progDisplay(progItem);
    
    
  } else if ( timePos == 6 ) {
    if ( chg == true && sched[progItem - 1].Slope < 9 ) {
        sched[progItem - 1].Slope++;  
    } else if ( chg == false && sched[progItem - 1].Slope > 0 ) {
       sched[progItem - 1].Slope--; 
    }
    Serial.print ( sched[progItem - 1].Slope );
    Serial.print ("\n");
    progDisplay(progItem);
    
  }
  
  
  
  
}

void progButton ( ) {
  timePos++;
  if (timePos > 6) { 
    timePos = 0; 
    
  }
  //  PROGRAM xx
  //  HA HH:MM B VVV M 
  //  01234567890123456


  char  z[3] = "00";
  switch (timePos) {
    case 0:
      strcpy(z , "08");
      break;
    case 1:
      strcpy(z,  "00");
      break;
    case 2:
      strcpy(z, "03");
      break;
    case 3:
      strcpy(z, "06");
      break;
    case 4:
      strcpy(z, "09");
      break;
    case 5:
      strcpy(z, "11");
      break;
    case 6:
      strcpy(z,"15");
      break;
  }
  strcpy( cursorPos, "?x");
  strcat( cursorPos, z);
  if ( timePos > 0 ) {
    strcat( cursorPos, "?y1");
  } else {
    strcat( cursorPos, "?y0");
  }
  
  mySerial.print(cursorPos);
  
  
}

void progDisplay ( byte prog  )
{
 
  mySerial.print("?x08?y0");
  printDigits2( prog );
  
  
  mySerial.print("?x00?y1");
  byte h;
  byte m;
  
  h = sched[prog - 1].Time / 60;
  m = sched[prog - 1].Time - (h * 60);
  
  if ( sched[prog - 1].Active == true ) {
    mySerial.print ("ON "); 
  } else {
    mySerial.print ("   ");
  } 
  
  printDigits2(h);
  mySerial.print (':');
  printDigits2(m);
  mySerial.print (' ');
  
  mySerial.print ( sched[prog - 1 ].Bar );
  mySerial.print (' ');
  
  
  if ( sched[prog - 1].Value < 100 ) mySerial.print('0');
  if ( sched[prog - 1].Value < 10 ) mySerial.print('0');
  
  
  mySerial.print ( sched[prog - 1].Value );
  
  mySerial.print(' ');
  mySerial.print( sched[prog - 1].Slope ); 
  
}

void printDigits3( int v ) {

  if ( v < 100 ) mySerial.print('0');
  if ( v < 10  ) mySerial.print('0');
  mySerial.print( v ); 
}


void fansEncoder ( boolean chg ) {
  fanMode_t ct = fans[timePos].getMode();
 
  fanMode_t nt;
  if( chg == true ) {
     switch ( ct ) {
      case fanOn:
         nt = fanOff;
         break;
      case fanOff:
         nt = fanAuto;
         break;
      case fanAuto:
         nt = fanOn;
         break;
     }
   
  } else {
   
     switch ( ct ) {
      case fanOn:
         nt = fanAuto;
         break;
      case fanOff:
         nt = fanOn;
         break;
      case fanAuto:
         nt = fanOff;
         break;
     }
  } 
  fans[ timePos ].setMode( nt );
  displayFansSet();
  
}

void fansButton () {
    timePos++;
  if (timePos > 3) { 
    timePos = 0; 
      
    for ( int x = 0; x < 4; x++ ) {
      fans[x].save();
    }
     
    
  }
  char  z[3] = "00";
  switch (timePos) {
    case 0:
      strcpy(z , "02");
      break;
    case 1:
      strcpy(z,  "06");
      break;
    case 2:
      strcpy(z, "10");
      break;
    case 3:
      strcpy(z, "14");
      break;

  }
  strcpy( cursorPos, "?x");
  strcat( cursorPos, z);
  strcat( cursorPos, "?y1");
  
  mySerial.print(cursorPos);
  
}

void displayTimeSet( boolean refresh ) {
  
 
  
  if (refresh == true )
  {
  
    mySerial.print("?x00?y1?c2");
  
    dualDig( setTm.Hour ) ;
    mySerial.print(':');
    dualDig( setTm.Minute  ) ; 
    mySerial.print(' ');
    dualDig( setTm.Month ) ;
    mySerial.print('/');
    dualDig( setTm.Day ) ;
    mySerial.print('/');
    dualDig( setTm.Year + 1970 ) ;
    
    mySerial.print(cursorPos);
  }
  
}
void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  if ( second() % 2 == 0 )
      mySerial.print (':');
   else 
      mySerial.print (' ');
      
  if(digits < 10) {
    mySerial.print('0');
  }
  mySerial.print(digits);
}

void printDigits2(int digits) {
  if ( digits < 10 ) {
    mySerial.print('0');
  }
  mySerial.print (digits);
}

  /*  code to process time sync messages from the serial port   */
#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message

time_t processSyncMessage() {
  // return the time if a valid sync message is received on the serial port.
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ; 
    Serial.print(c);  
    if( c == TIME_HEADER ) {       
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c = Serial.read();          
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }   
      return pctime; 
    }  
  }
  return 0;
}

void timeButton() {
  timePos++;
  if (timePos > 4) { 
    timePos = 0; 
    setTm.Second = 0;
    time_t newTime = makeTime( setTm );
    setTime( newTime );
    RTC.set( newTime );
    
  }
  char  z[3] = "00";
  switch (timePos) {
    case 0:
      strcpy(z , "00");
      break;
    case 1:
      strcpy(z,  "03");
      break;
    case 2:
      strcpy(z, "06");
      break;
    case 3:
      strcpy(z, "09");
      break;
     case 4:
      strcpy(z, "12");
      break;
  }
  strcpy( cursorPos, "?x");
  strcat( cursorPos, z);
  strcat( cursorPos, "?y1");
  
  mySerial.print(cursorPos);
  
}

void timeEncoder ( boolean chg ) {
  
   uint8_t dL = monthDays[ setTm.Month - 1 ];
   switch (timePos) {
     case 0:
       if (chg == true && setTm.Hour < 23) 
         setTm.Hour++;
       else if (chg == true && setTm.Hour == 23)
         setTm.Hour =  0;
       else if (chg == false && setTm.Hour > 0)
          setTm.Hour --;
       else if (chg == false && setTm.Hour == 0)
          setTm.Hour = 23;
       break;
     case 1:
       if (chg == true && setTm.Minute < 59) 
         setTm.Minute++;
       else if (chg == true && setTm.Minute == 59)
         setTm.Minute =  0;
       else if (chg == false && setTm.Minute > 0)
          setTm.Minute --;
       else if (chg == false && setTm.Minute == 0)
          setTm.Minute = 59;
       break;
     case 2:
       if (chg == true && setTm.Month < 12) 
         setTm.Month++;
       else if (chg == true && setTm.Month == 12)
         setTm.Month =  1;
       else if (chg == false && setTm.Month > 1)
          setTm.Month --;
       else if (chg == false && setTm.Month == 1)
          setTm.Month = 12;
       
       dL = monthDays[ setTm.Month - 1 ];
       if (setTm.Day > dL)  setTm.Day = dL;
       break;
      
     case 3:
      if (chg == true && setTm.Day < dL) 
         setTm.Day++;
       else if (chg == true && setTm.Day == dL)
         setTm.Day =  1;
       else if (chg == false && setTm.Day > 1)
          setTm.Day --;
       else if (chg == false && setTm.Day == 1)
          setTm.Day = dL;
       break;
     case 4:
       if (chg == true ) 
         setTm.Year++;
       else if (chg == false && setTm.Year > 1)
          setTm.Year --;
       break;
   }
   displayTimeSet(true);


  
}

void manualEncoder ( boolean chg ) {
  if ( timePos > 2 )
    return;
   
   
  byte inc = 10;
    if ( millis()  > pmillis + 100 ) {
      inc = 1;
     
    }
    
    pmillis = millis();
  
  if ( chg == true ) {
      bar[ timePos ].Target += inc;
  }
  else {
      bar[ timePos ].Target -= inc;
  } 
  
  if (   bar[ timePos ].Target < 0 ) {
      bar[ timePos ].Target = 0;
  }
  
  if (   bar[ timePos ].Target > 255 ) {
      bar[ timePos ].Target = 255;
  }
  manualDisplay();
  
}

void manualButton()
{
  timePos++;
  if (timePos > 2 ) timePos = 0;
  
  manualDisplay();
  
}

void manualDisplay()
{
  mySerial.print("?c2?x00?y1F");
  printDigits3( bar[0].Target );
  mySerial.print(" M");
  printDigits3( bar[1].Target );
  mySerial.print(" B");
  printDigits3( bar[2].Target );
  
   mySerial.print("?x");
  if ( timePos == 0 ) 
    mySerial.print("00");
  if ( timePos == 1 ) 
    mySerial.print("05");
  if ( timePos == 2 ) 
    mySerial.print("10");
  mySerial.print("?y1");
  
}

void menuEncoder ( boolean chg ) {
 
  
  if ( chg == true ) 
     menuItem++;
  else 
     menuItem--;
     
     if ( menuItem > 250) 
      menuItem = 6;
    if ( menuItem > 6) 
      menuItem = 0;
   

      mySerial.print("?x00?y0");
      mySerial.print(menu[menuItem] );
      
      clearLine2();
      
      KnobB.setPulse( &empty );
      KnobB.setButton( &empty );
      KnobA.setDelay ( 100 );
      if (menuItem == 4) {
         timePos = 0;
         prevMillis = millis();
          time_t t = now();
          breakTime( t, setTm);
       
         KnobB.setPulse( &timeEncoder);
         KnobB.setButton( &timeButton );
         displayTimeSet(true);
      } else if ( menuItem == 0 ) {
         ResetProg();
      } else if (menuItem == 1 ) {
        ResetProg();
        timePos = 0;
        KnobB.setPulse ( &manualEncoder );
        KnobB.setButton( &manualButton );
        manualDisplay();
      } else if (menuItem == 3 ) {
        timePos = 0;
        KnobB.setPulse ( &fansEncoder );
        KnobB.setButton ( &fansButton );
        displayFansSet();
      } else if ( menuItem == 5 ) {
        timePos = 0;
        KnobB.setPulse ( &progEncoder );
        KnobB.setButton ( &progButton );
        KnobA.setDelay ( 2000 );
        progItem = 1;
        progDisplay( progItem );
        
      } else if (menuItem == 6 ) {
        prevMillis = millis();
        displayFreeMem();
      }
        
      
      //mySerial.print("?x00?y1");
      //mySerial.print(menuItem );
      
}

void menuButton () {
  if ( menuItem == 5 ) {
      mySerial.print("?x00?y1SAVING ");
      printDigits2( progItem );
      mySerial.print(".......");
      delay(1000);
      SaveSchedule(progItem - 1);
      progDisplay(progItem);
  }
  
  
}

void clearLine2() {
  mySerial.print("?x00?y1                ");               
  
}



void empty() {
}

void empty( boolean chg) {}




